// This Pine Script® code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/ MPL-2.0
//@version=6
indicator("Supertrend with Entry, TP1, TP2 & TP3 [CURRENT]", "Supertrend CURRENT", overlay = true, max_boxes_count = 20, max_lines_count = 20, max_labels_count = 50)

// --- Input groups ---
string CALCULATION_GROUP = "Calculation"
string DISPLAY_GROUP = "Display"
string TRADE_LEVEL_GROUP = "Trade levels"
string STYLE_GROUP = "Style"

// --- Inputs ---
factorInput = input.float(2.5, "Factor", minval = 0.01, step = 0.01, tooltip = "Multiplier for the ATR-based Supertrend distance.", group = CALCULATION_GROUP)
atrPeriodInput = input.int(14, "ATR period", minval = 1, tooltip = "Number of bars used to calculate ATR.", group = CALCULATION_GROUP)
showSignalsInput = input.bool(true, "Show signals", tooltip = "Displays buy and sell signals when the Supertrend direction changes.", group = DISPLAY_GROUP)
onlyStrongAdxSignalsInput = input.bool(false, "Only signal when ADX is strong", tooltip = "When enabled, BUY and SELL signals appear only when ADX is above the selected threshold.", group = DISPLAY_GROUP)
useEma200FilterInput = input.bool(false, "EMA 200 direction filter", tooltip = "Allows long signals only above EMA 200 and short signals only below EMA 200.", group = DISPLAY_GROUP)
showFillInput = input.bool(true, "Fill trend area", tooltip = "Fills the area between price and the Supertrend with the trend color.", group = DISPLAY_GROUP)
showLevelsInput = input.bool(true, "Show Entry, TP1, TP2, TP3 and SL", tooltip = "Displays the latest setup's entry, take-profit and stop-loss lines.", group = DISPLAY_GROUP)
showBoxesInput = input.bool(true, "Show trade zones", tooltip = "Displays profit and loss zones extending to the right of the chart.", group = DISPLAY_GROUP)
showTpMarksInput = input.bool(true, "Mark reached take-profits", tooltip = "Marks TP1, TP2 and TP3 when price reaches each level.", group = DISPLAY_GROUP)
showPriceLabelsInput = input.bool(true, "Show price labels", tooltip = "Displays exact setup prices in labels to the right of the chart.", group = DISPLAY_GROUP)
priceLabelOffsetInput = input.int(15, "Price-label offset", minval = 0, maxval = 500, tooltip = "Number of bars to offset Entry, TP and SL labels to the right.", group = DISPLAY_GROUP)
showStatsInput = input.bool(true, "Show win-rate statistics", tooltip = "Displays completed setup statistics. A trade counts as a win as soon as TP1 is reached.", group = DISPLAY_GROUP)
showCandleColorsInput = input.bool(true, "Color candles by trend", tooltip = "Colors candles according to the current Supertrend direction.", group = DISPLAY_GROUP)
showAdxDashboardInput = input.bool(true, "Show ADX dashboard", tooltip = "Displays trend strength, direction and the ADX trading filter status.", group = DISPLAY_GROUP)
showMtfDashboardInput = input.bool(true, "Show multi-timeframe dashboard", tooltip = "Displays a bullish/bearish score from 0 to 100 for 5m, 15m, 1h, 4h and 1D.", group = DISPLAY_GROUP)
showTradeHistoryInput = input.bool(true, "Show trade history", tooltip = "Displays the 10 most recent completed trades or trades ended by an opposite signal, including direction, TP, RR and SL status.", group = DISPLAY_GROUP)
showKeyLevelsInput = input.bool(false, "Show key support/resistance levels", tooltip = "Automatically groups pivot levels into horizontal support and resistance levels.", group = DISPLAY_GROUP)
showTrendLinesInput = input.bool(true, "Show Supertrend lines", tooltip = "Displays the bullish and bearish Supertrend lines.", group = DISPLAY_GROUP)
showDiagonalTrendLinesInput = input.bool(false, "Show diagonal trendlines", tooltip = "Displays the latest confirmed diagonal support and resistance lines based on pivot points.", group = DISPLAY_GROUP)
showOnlyCurrentSlopeInput = input.bool(true, "Show only the current slope", tooltip = "In an uptrend, show only rising support; in a downtrend, show only falling resistance.", group = DISPLAY_GROUP)
showChannelInput = input.bool(false, "Show trend channel", tooltip = "Automatically draws a parallel trend channel from confirmed pivot points.", group = DISPLAY_GROUP)
showBreakoutSignalsInput = input.bool(false, "Show trendline/channel breakout signals", tooltip = "Creates a BUY or SELL signal when a confirmed candle closes through a diagonal trendline or channel.", group = DISPLAY_GROUP)
enableTp3ReentryInput = input.bool(false, "Enable Supertrend re-entry", tooltip = "After TP3, looks for a pullback to the Supertrend followed by confirmation in the trend direction.", group = DISPLAY_GROUP)
enableEmaReentryInput = input.bool(false, "Enable EMA re-entry", tooltip = "After TP3, looks for a pullback across the EMA and a recross in the trend direction.", group = DISPLAY_GROUP)
enableAggressiveEmaReentryInput = input.bool(false, "Enable aggressive EMA re-entry", tooltip = "After TP3, allows re-entry on an EMA touch and close back in the trend direction without waiting for a prior close across the EMA.", group = DISPLAY_GROUP)
emaReentryLengthInput = input.int(13, "Re-entry EMA length", options = [13, 9, 5], tooltip = "EMA length used for optional pullback re-entry after TP3.", group = CALCULATION_GROUP)
pivotLengthInput = input.int(5, "Pivot length", minval = 1, maxval = 50, tooltip = "Number of bars to the left and right required to confirm a swing high or swing low.", group = CALCULATION_GROUP)
keyLevelsCountInput = input.int(3, "Number of key levels", minval = 1, maxval = 5, tooltip = "Maximum number of support and resistance levels on each side.", group = CALCULATION_GROUP)
keyLevelToleranceAtrInput = input.float(0.5, "Level tolerance (ATR)", minval = 0.1, maxval = 3.0, step = 0.1, tooltip = "Pivot levels within this ATR distance are merged into one key level.", group = CALCULATION_GROUP)
adxLengthInput = input.int(14, "ADX DI length", minval = 1, tooltip = "Length used to calculate positive and negative directional movement.", group = CALCULATION_GROUP)
adxSmoothingInput = input.int(14, "ADX smoothing", minval = 1, tooltip = "Smoothing length for ADX.", group = CALCULATION_GROUP)
adxRangeThresholdInput = input.float(20.0, "ADX range threshold", minval = 1.0, step = 0.5, tooltip = "Below this value, the market is classified as ranging.", group = CALCULATION_GROUP)
adxStrongThresholdInput = input.float(25.0, "ADX trend threshold", minval = 1.0, step = 0.5, tooltip = "At or above this value, the trend is considered strong.", group = CALCULATION_GROUP)
signalAdxThresholdInput = input.float(50.0, "Signal ADX threshold", minval = 1.0, maxval = 100.0, step = 0.5, tooltip = "When the ADX signal filter is enabled, signals must have ADX above this value.", group = CALCULATION_GROUP)
neutralZoneHalfWidthInput = input.float(10.0, "Neutral zone ±", minval = 0.0, maxval = 49.0, step = 0.5, tooltip = "Half-width of the neutral zone around 50 in the multi-timeframe dashboard.", group = CALCULATION_GROUP)
slAtrMultiplierInput = input.float(1.5, "Stop-loss ATR multiplier", minval = 0.1, step = 0.1, tooltip = "ATR distance from the entry used to calculate the stop loss.", group = TRADE_LEVEL_GROUP)
tp1RiskRewardInput = input.float(1.0, "TP1 risk/reward", minval = 0.1, step = 0.1, tooltip = "TP1 distance as a multiple of the stop-loss risk.", group = TRADE_LEVEL_GROUP)
tp2RiskRewardInput = input.float(2.0, "TP2 risk/reward", minval = 0.1, step = 0.1, tooltip = "TP2 distance as a multiple of the stop-loss risk.", group = TRADE_LEVEL_GROUP)
tp3RiskRewardInput = input.float(3.0, "TP3 risk/reward", minval = 0.1, step = 0.1, tooltip = "TP3 distance as a multiple of the stop-loss risk.", group = TRADE_LEVEL_GROUP)
upColorInput = input.color(#089981, "Uptrend", tooltip = "Color used for the Supertrend during an uptrend.", group = STYLE_GROUP)
downColorInput = input.color(#f23645, "Downtrend", tooltip = "Color used for the Supertrend during a downtrend.", group = STYLE_GROUP)
entryColorInput = input.color(#5b9cf6, "Entry", tooltip = "Color of the entry level.", group = STYLE_GROUP)
takeProfit1ColorInput = input.color(#26a69a, "TP1", tooltip = "Color of the first take-profit level.", group = STYLE_GROUP)
takeProfit2ColorInput = input.color(#089981, "TP2", tooltip = "Color of the second take-profit level.", group = STYLE_GROUP)
takeProfit3ColorInput = input.color(#00695c, "TP3", tooltip = "Color of the third take-profit level.", group = STYLE_GROUP)
stopLossColorInput = input.color(#f23645, "Stop loss", tooltip = "Color of the stop-loss level.", group = STYLE_GROUP)
candleUpColorInput = input.color(#00ff00, "Bullish candles", tooltip = "Candle color during an uptrend.", group = STYLE_GROUP)
candleDownColorInput = input.color(#ff0000, "Bearish candles", tooltip = "Candle color during a downtrend.", group = STYLE_GROUP)
candleTransparencyInput = input.int(0, "Candle transparency", minval = 0, maxval = 100, tooltip = "Transparency of trend-colored candles. 0 is fully opaque.", group = STYLE_GROUP)
supportTrendLineColorInput = input.color(#089981, "Support trendline", tooltip = "Color of the diagonal support line.", group = STYLE_GROUP)
resistanceTrendLineColorInput = input.color(#f23645, "Resistance trendline", tooltip = "Color of the diagonal resistance line.", group = STYLE_GROUP)
channelColorInput = input.color(#5b9cf6, "Trend channel", tooltip = "Color of the upper and lower channel lines.", group = STYLE_GROUP)
channelFillTransparencyInput = input.int(94, "Channel fill transparency", minval = 0, maxval = 100, tooltip = "Transparency of the area inside the trend channel.", group = STYLE_GROUP)

// --- Helper functions ---
createPriceLabel(int x, float price, string title, color labelColor) =>
    label.new(x = x, y = price, text = title + "  " + str.tostring(price, format.mintick), style = label.style_label_left, color = labelColor, textcolor = color.white, size = size.small)

trendScore(float trendDirection, float adx) =>
    float boundedAdx = math.min(nz(adx), 50.0)
    na(trendDirection) or na(adx) ? 50.0 : adx < adxRangeThresholdInput ? 50.0 : trendDirection < 0 ? 50.0 + boundedAdx : 50.0 - boundedAdx

trendState(float trendDirection, float adx) =>
    float score = trendScore(trendDirection, adx)
    score >= 50.0 - neutralZoneHalfWidthInput and score <= 50.0 + neutralZoneHalfWidthInput ? "Neutral" : trendDirection < 0 ? "Bullish" : "Bearish"

scoreColor(float score) =>
    score > 50.0 + neutralZoneHalfWidthInput ? upColorInput : score < 50.0 - neutralZoneHalfWidthInput ? downColorInput : chart.fg_color

// --- Supertrend, ATR, ADX and EMA calculations ---
[supertrend, direction] = ta.supertrend(factorInput, atrPeriodInput)
atrValue = ta.atr(atrPeriodInput)
[diPlus, diMinus, adxValue] = ta.dmi(adxLengthInput, adxSmoothingInput)
emaReentryValue = ta.ema(close, emaReentryLengthInput)
ema200Value = ta.ema(close, 200)
emaCrossUp = ta.crossover(close, emaReentryValue)
emaCrossDown = ta.crossunder(close, emaReentryValue)

[direction5m, adx5m] = request.security(syminfo.tickerid, "5", [direction, adxValue], gaps = barmerge.gaps_off, lookahead = barmerge.lookahead_off)
[direction15m, adx15m] = request.security(syminfo.tickerid, "15", [direction, adxValue], gaps = barmerge.gaps_off, lookahead = barmerge.lookahead_off)
[direction1h, adx1h] = request.security(syminfo.tickerid, "60", [direction, adxValue], gaps = barmerge.gaps_off, lookahead = barmerge.lookahead_off)
[direction4h, adx4h] = request.security(syminfo.tickerid, "240", [direction, adxValue], gaps = barmerge.gaps_off, lookahead = barmerge.lookahead_off)
[direction1d, adx1d] = request.security(syminfo.tickerid, "D", [direction, adxValue], gaps = barmerge.gaps_off, lookahead = barmerge.lookahead_off)
score5m = trendScore(direction5m, adx5m)
score15m = trendScore(direction15m, adx15m)
score1h = trendScore(direction1h, adx1h)
score4h = trendScore(direction4h, adx4h)
score1d = trendScore(direction1d, adx1d)
state5m = trendState(direction5m, adx5m)
state15m = trendState(direction15m, adx15m)
state1h = trendState(direction1h, adx1h)
state4h = trendState(direction4h, adx4h)
state1d = trendState(direction1d, adx1d)

isUpTrend = direction < 0
isDownTrend = direction > 0
upTrend = isUpTrend ? supertrend : na
downTrend = isDownTrend ? supertrend : na
supertrendBuySignal = ta.crossunder(direction, 0)
supertrendSellSignal = ta.crossover(direction, 0)
pivotLow = ta.pivotlow(low, pivotLengthInput, pivotLengthInput)
pivotHigh = ta.pivothigh(high, pivotLengthInput, pivotLengthInput)

// --- Pivot data for breakout signals ---
var float breakoutPreviousSupportPrice = na
var int breakoutPreviousSupportBar = na
var float breakoutLastSupportPrice = na
var int breakoutLastSupportBar = na
var float breakoutPreviousResistancePrice = na
var int breakoutPreviousResistanceBar = na
var float breakoutLastResistancePrice = na
var int breakoutLastResistanceBar = na
if not na(pivotLow)
    breakoutPreviousSupportPrice := breakoutLastSupportPrice
    breakoutPreviousSupportBar := breakoutLastSupportBar
    breakoutLastSupportPrice := pivotLow
    breakoutLastSupportBar := bar_index - pivotLengthInput
if not na(pivotHigh)
    breakoutPreviousResistancePrice := breakoutLastResistancePrice
    breakoutPreviousResistanceBar := breakoutLastResistanceBar
    breakoutLastResistancePrice := pivotHigh
    breakoutLastResistanceBar := bar_index - pivotLengthInput

// --- Re-entry and breakout conditions ---
var bool reentryLongArmed = false
var bool reentryShortArmed = false
var bool emaLongPullbackArmed = false
var bool emaShortPullbackArmed = false
bool reentryBuySignal = enableTp3ReentryInput and reentryLongArmed and isUpTrend and not na(supertrend) and low <= supertrend and close > supertrend
bool reentrySellSignal = enableTp3ReentryInput and reentryShortArmed and isDownTrend and not na(supertrend) and high >= supertrend and close < supertrend
bool emaReentryBuySignal = enableEmaReentryInput and reentryLongArmed and isUpTrend and emaLongPullbackArmed and emaCrossUp
bool emaReentrySellSignal = enableEmaReentryInput and reentryShortArmed and isDownTrend and emaShortPullbackArmed and emaCrossDown
bool aggressiveEmaReentryBuySignal = enableAggressiveEmaReentryInput and reentryLongArmed and isUpTrend and not na(emaReentryValue) and low <= emaReentryValue and close > emaReentryValue
bool aggressiveEmaReentrySellSignal = enableAggressiveEmaReentryInput and reentryShortArmed and isDownTrend and not na(emaReentryValue) and high >= emaReentryValue and close < emaReentryValue

float breakoutSupportSlope = not na(breakoutPreviousSupportBar) and not na(breakoutLastSupportBar) and breakoutLastSupportBar != breakoutPreviousSupportBar ? (breakoutLastSupportPrice - breakoutPreviousSupportPrice) / (breakoutLastSupportBar - breakoutPreviousSupportBar) : na
float breakoutSupportNow = not na(breakoutSupportSlope) ? breakoutPreviousSupportPrice + breakoutSupportSlope * (bar_index - breakoutPreviousSupportBar) : na
float breakoutSupportPrevious = not na(breakoutSupportSlope) ? breakoutPreviousSupportPrice + breakoutSupportSlope * (bar_index - 1 - breakoutPreviousSupportBar) : na
float breakoutSupportAtResistance = not na(breakoutSupportSlope) and not na(breakoutLastResistanceBar) ? breakoutPreviousSupportPrice + breakoutSupportSlope * (breakoutLastResistanceBar - breakoutPreviousSupportBar) : na
float breakoutUpChannelWidth = not na(breakoutSupportAtResistance) and not na(breakoutLastResistancePrice) ? breakoutLastResistancePrice - breakoutSupportAtResistance : na
bool breakoutUpChannelValid = not na(breakoutUpChannelWidth) and breakoutUpChannelWidth > 0
float breakoutResistanceSlope = not na(breakoutPreviousResistanceBar) and not na(breakoutLastResistanceBar) and breakoutLastResistanceBar != breakoutPreviousResistanceBar ? (breakoutLastResistancePrice - breakoutPreviousResistancePrice) / (breakoutLastResistanceBar - breakoutPreviousResistanceBar) : na
float breakoutResistanceNow = not na(breakoutResistanceSlope) ? breakoutPreviousResistancePrice + breakoutResistanceSlope * (bar_index - breakoutPreviousResistanceBar) : na
float breakoutResistancePrevious = not na(breakoutResistanceSlope) ? breakoutPreviousResistancePrice + breakoutResistanceSlope * (bar_index - 1 - breakoutPreviousResistanceBar) : na
float breakoutResistanceAtSupport = not na(breakoutResistanceSlope) and not na(breakoutLastSupportBar) ? breakoutPreviousResistancePrice + breakoutResistanceSlope * (breakoutLastSupportBar - breakoutPreviousResistanceBar) : na
float breakoutDownChannelWidth = not na(breakoutResistanceAtSupport) and not na(breakoutLastSupportPrice) ? breakoutResistanceAtSupport - breakoutLastSupportPrice : na
bool breakoutDownChannelValid = not na(breakoutDownChannelWidth) and breakoutDownChannelWidth > 0
float breakoutUpperNow = breakoutUpChannelValid ? breakoutSupportNow + breakoutUpChannelWidth : breakoutResistanceNow
float breakoutUpperPrevious = breakoutUpChannelValid ? breakoutSupportPrevious + breakoutUpChannelWidth : breakoutResistancePrevious
float breakoutLowerNow = breakoutDownChannelValid ? breakoutResistanceNow - breakoutDownChannelWidth : breakoutSupportNow
float breakoutLowerPrevious = breakoutDownChannelValid ? breakoutResistancePrevious - breakoutDownChannelWidth : breakoutSupportPrevious
bool breakoutBuySignal = showBreakoutSignalsInput and not na(breakoutUpperNow) and not na(breakoutUpperPrevious) and close > breakoutUpperNow and close[1] <= breakoutUpperPrevious
bool breakoutSellSignal = showBreakoutSignalsInput and not na(breakoutLowerNow) and not na(breakoutLowerPrevious) and close < breakoutLowerNow and close[1] >= breakoutLowerPrevious

bool unfilteredBuySignal = supertrendBuySignal or breakoutBuySignal or reentryBuySignal or emaReentryBuySignal
bool unfilteredSellSignal = supertrendSellSignal or breakoutSellSignal or reentrySellSignal or emaReentrySellSignal
bool adxSignalFilterPassed = not onlyStrongAdxSignalsInput or (not na(adxValue) and adxValue > signalAdxThresholdInput)
bool ema200LongAllowed = not useEma200FilterInput or close > ema200Value
bool ema200ShortAllowed = not useEma200FilterInput or close < ema200Value
bool buySignal = (unfilteredBuySignal or aggressiveEmaReentryBuySignal) and adxSignalFilterPassed and ema200LongAllowed
bool sellSignal = (unfilteredSellSignal or aggressiveEmaReentrySellSignal) and adxSignalFilterPassed and ema200ShortAllowed
if enableEmaReentryInput and reentryLongArmed and isUpTrend and emaCrossDown
    emaLongPullbackArmed := true
if enableEmaReentryInput and reentryShortArmed and isDownTrend and emaCrossUp
    emaShortPullbackArmed := true

// --- Trade levels and statistics ---
var float entryLevel = na
var float takeProfit1Level = na
var float takeProfit2Level = na
var float takeProfit3Level = na
var float stopLossLevel = na
var int tradeDirection = 0
var bool takeProfit1Reached = false
var bool takeProfit2Reached = false
var bool takeProfit3Reached = false
var bool tradeResolved = false
var int totalSignals = 0
var int winningTrades = 0
var int losingTrades = 0
var float totalProfitR = 0.0
var bool tradeHistoryRecorded = false
var array<string> tradeDirectionHistory = array.new_string(0)
var array<string> tradeOutcomeHistory = array.new_string(0)
var array<float> tradeRrHistory = array.new_float(0)
var array<string> tradeSlHistory = array.new_string(0)
bool takeProfit1HitEvent = false
bool takeProfit2HitEvent = false
bool takeProfit3HitEvent = false
var int tradeStartBar = na
var line entryLevelLine = na
var line takeProfit1LevelLine = na
var line takeProfit2LevelLine = na
var line takeProfit3LevelLine = na
var line stopLossLevelLine = na
var line supportTrendLine = na
var line resistanceTrendLine = na
var float previousSupportPivotPrice = na
var int previousSupportPivotBar = na
var float lastSupportPivotPrice = na
var int lastSupportPivotBar = na
var float previousResistancePivotPrice = na
var int previousResistancePivotBar = na
var float lastResistancePivotPrice = na
var int lastResistancePivotBar = na
var line channelLowerLine = na
var line channelUpperLine = na
var linefill channelFill = na
var array<float> keySupportPrices = array.new_float(0)
var array<int> keySupportTouches = array.new_int(0)
var array<line> keySupportLines = array.new_line(0)
var array<float> keyResistancePrices = array.new_float(0)
var array<int> keyResistanceTouches = array.new_int(0)
var array<line> keyResistanceLines = array.new_line(0)

// Record the previous trade when an opposite signal occurs.
if (buySignal or sellSignal) and tradeDirection != 0 and not tradeHistoryRecorded
    string previousDirection = tradeDirection == 1 ? "Long" : "Short"
    string previousOutcome = takeProfit3Reached ? "TP3" : takeProfit2Reached ? "TP2" : takeProfit1Reached ? "TP1" : "REV"
    float previousRr = takeProfit3Reached ? tp3RiskRewardInput : takeProfit2Reached ? tp2RiskRewardInput : takeProfit1Reached ? tp1RiskRewardInput : 0.0
    array.unshift(tradeDirectionHistory, previousDirection)
    array.unshift(tradeOutcomeHistory, previousOutcome)
    array.unshift(tradeRrHistory, previousRr)
    array.unshift(tradeSlHistory, "No")
    if array.size(tradeDirectionHistory) > 10
        array.pop(tradeDirectionHistory)
        array.pop(tradeOutcomeHistory)
        array.pop(tradeRrHistory)
        array.pop(tradeSlHistory)
    tradeHistoryRecorded := true

if buySignal
    entryLevel := close
    stopLossLevel := entryLevel - atrValue * slAtrMultiplierInput
    float riskDistance = entryLevel - stopLossLevel
    takeProfit1Level := entryLevel + riskDistance * tp1RiskRewardInput
    takeProfit2Level := entryLevel + riskDistance * tp2RiskRewardInput
    takeProfit3Level := entryLevel + riskDistance * tp3RiskRewardInput
    tradeDirection := 1
    takeProfit1Reached := false
    takeProfit2Reached := false
    takeProfit3Reached := false
    tradeResolved := false
    tradeHistoryRecorded := false
    reentryLongArmed := false
    reentryShortArmed := false
    emaLongPullbackArmed := false
    emaShortPullbackArmed := false
    totalSignals += 1
if sellSignal
    entryLevel := close
    stopLossLevel := entryLevel + atrValue * slAtrMultiplierInput
    float riskDistance = stopLossLevel - entryLevel
    takeProfit1Level := entryLevel - riskDistance * tp1RiskRewardInput
    takeProfit2Level := entryLevel - riskDistance * tp2RiskRewardInput
    takeProfit3Level := entryLevel - riskDistance * tp3RiskRewardInput
    tradeDirection := -1
    takeProfit1Reached := false
    takeProfit2Reached := false
    takeProfit3Reached := false
    tradeResolved := false
    tradeHistoryRecorded := false
    reentryLongArmed := false
    reentryShortArmed := false
    emaLongPullbackArmed := false
    emaShortPullbackArmed := false
    totalSignals += 1

if not (buySignal or sellSignal) and tradeDirection != 0 and not tradeResolved
    bool stopHitForStats = tradeDirection == 1 ? low <= stopLossLevel : high >= stopLossLevel
    bool takeProfit1HitForStats = tradeDirection == 1 ? high >= takeProfit1Level : low <= takeProfit1Level
    if stopHitForStats
        losingTrades += 1
        totalProfitR -= 1.0
        if not tradeHistoryRecorded
            array.unshift(tradeDirectionHistory, tradeDirection == 1 ? "Long" : "Short")
            array.unshift(tradeOutcomeHistory, "SL")
            array.unshift(tradeRrHistory, -1.0)
            array.unshift(tradeSlHistory, "Yes")
            if array.size(tradeDirectionHistory) > 10
                array.pop(tradeDirectionHistory)
                array.pop(tradeOutcomeHistory)
                array.pop(tradeRrHistory)
                array.pop(tradeSlHistory)
            tradeHistoryRecorded := true
        tradeResolved := true
        tradeDirection := 0
    else if takeProfit1HitForStats
        winningTrades += 1
        totalProfitR += tp1RiskRewardInput
        tradeResolved := true

if not (buySignal or sellSignal) and tradeDirection != 0
    if tradeDirection == 1 and not takeProfit1Reached and not na(takeProfit1Level) and high >= takeProfit1Level
        takeProfit1Reached := true
        takeProfit1HitEvent := true
    if tradeDirection == 1 and not takeProfit2Reached and not na(takeProfit2Level) and high >= takeProfit2Level
        takeProfit2Reached := true
        takeProfit2HitEvent := true
    if tradeDirection == 1 and not takeProfit3Reached and not na(takeProfit3Level) and high >= takeProfit3Level
        takeProfit3Reached := true
        reentryLongArmed := true
        emaLongPullbackArmed := false
        takeProfit3HitEvent := true
        if not tradeHistoryRecorded
            array.unshift(tradeDirectionHistory, "Long")
            array.unshift(tradeOutcomeHistory, "TP3")
            array.unshift(tradeRrHistory, tp3RiskRewardInput)
            array.unshift(tradeSlHistory, "No")
            if array.size(tradeDirectionHistory) > 10
                array.pop(tradeDirectionHistory)
                array.pop(tradeOutcomeHistory)
                array.pop(tradeRrHistory)
                array.pop(tradeSlHistory)
            tradeHistoryRecorded := true
    if tradeDirection == -1 and not takeProfit1Reached and not na(takeProfit1Level) and low <= takeProfit1Level
        takeProfit1Reached := true
        takeProfit1HitEvent := true
    if tradeDirection == -1 and not takeProfit2Reached and not na(takeProfit2Level) and low <= takeProfit2Level
        takeProfit2Reached := true
        takeProfit2HitEvent := true
    if tradeDirection == -1 and not takeProfit3Reached and not na(takeProfit3Level) and low <= takeProfit3Level
        takeProfit3Reached := true
        reentryShortArmed := true
        emaShortPullbackArmed := false
        takeProfit3HitEvent := true
        if not tradeHistoryRecorded
            array.unshift(tradeDirectionHistory, "Short")
            array.unshift(tradeOutcomeHistory, "TP3")
            array.unshift(tradeRrHistory, tp3RiskRewardInput)
            array.unshift(tradeSlHistory, "No")
            if array.size(tradeDirectionHistory) > 10
                array.pop(tradeDirectionHistory)
                array.pop(tradeOutcomeHistory)
                array.pop(tradeRrHistory)
                array.pop(tradeSlHistory)
            tradeHistoryRecorded := true

// --- Horizontal trade-level lines ---
if buySignal or sellSignal
    tradeStartBar := bar_index
    if not na(entryLevelLine)
        line.delete(entryLevelLine)
    if not na(takeProfit1LevelLine)
        line.delete(takeProfit1LevelLine)
    if not na(takeProfit2LevelLine)
        line.delete(takeProfit2LevelLine)
    if not na(takeProfit3LevelLine)
        line.delete(takeProfit3LevelLine)
    if not na(stopLossLevelLine)
        line.delete(stopLossLevelLine)
    entryLevelLine := na
    takeProfit1LevelLine := na
    takeProfit2LevelLine := na
    takeProfit3LevelLine := na
    stopLossLevelLine := na
if showLevelsInput and not na(entryLevel) and not na(tradeStartBar)
    int lineEndBar = bar_index + priceLabelOffsetInput
    if na(entryLevelLine)
        entryLevelLine := line.new(x1 = tradeStartBar, y1 = entryLevel, x2 = lineEndBar, y2 = entryLevel, xloc = xloc.bar_index, extend = extend.none, color = entryColorInput, style = line.style_dashed, width = 2)
        takeProfit1LevelLine := line.new(x1 = tradeStartBar, y1 = takeProfit1Level, x2 = lineEndBar, y2 = takeProfit1Level, xloc = xloc.bar_index, extend = extend.none, color = takeProfit1ColorInput, style = line.style_dashed, width = 1)
        takeProfit2LevelLine := line.new(x1 = tradeStartBar, y1 = takeProfit2Level, x2 = lineEndBar, y2 = takeProfit2Level, xloc = xloc.bar_index, extend = extend.none, color = takeProfit2ColorInput, style = line.style_dashed, width = 1)
        takeProfit3LevelLine := line.new(x1 = tradeStartBar, y1 = takeProfit3Level, x2 = lineEndBar, y2 = takeProfit3Level, xloc = xloc.bar_index, extend = extend.none, color = takeProfit3ColorInput, style = line.style_dashed, width = 1)
        stopLossLevelLine := line.new(x1 = tradeStartBar, y1 = stopLossLevel, x2 = lineEndBar, y2 = stopLossLevel, xloc = xloc.bar_index, extend = extend.none, color = stopLossColorInput, style = line.style_dashed, width = 2)
    else
        line.set_x2(entryLevelLine, lineEndBar)
        line.set_x2(takeProfit1LevelLine, lineEndBar)
        line.set_x2(takeProfit2LevelLine, lineEndBar)
        line.set_x2(takeProfit3LevelLine, lineEndBar)
        line.set_x2(stopLossLevelLine, lineEndBar)
if not showLevelsInput
    if not na(entryLevelLine)
        line.delete(entryLevelLine)
        entryLevelLine := na
    if not na(takeProfit1LevelLine)
        line.delete(takeProfit1LevelLine)
        takeProfit1LevelLine := na
    if not na(takeProfit2LevelLine)
        line.delete(takeProfit2LevelLine)
        takeProfit2LevelLine := na
    if not na(takeProfit3LevelLine)
        line.delete(takeProfit3LevelLine)
        takeProfit3LevelLine := na
    if not na(stopLossLevelLine)
        line.delete(stopLossLevelLine)
        stopLossLevelLine := na

// --- Diagonal support and resistance lines ---
if not na(pivotLow)
    previousSupportPivotPrice := lastSupportPivotPrice
    previousSupportPivotBar := lastSupportPivotBar
    lastSupportPivotPrice := pivotLow
    lastSupportPivotBar := bar_index - pivotLengthInput
if not na(pivotHigh)
    previousResistancePivotPrice := lastResistancePivotPrice
    previousResistancePivotBar := lastResistancePivotBar
    lastResistancePivotPrice := pivotHigh
    lastResistancePivotBar := bar_index - pivotLengthInput
bool risingSupport = not na(previousSupportPivotPrice) and not na(lastSupportPivotPrice) and lastSupportPivotPrice > previousSupportPivotPrice
bool fallingResistance = not na(previousResistancePivotPrice) and not na(lastResistancePivotPrice) and lastResistancePivotPrice < previousResistancePivotPrice
bool allowSupportLine = showDiagonalTrendLinesInput and (not showOnlyCurrentSlopeInput or (isUpTrend and risingSupport))
bool allowResistanceLine = showDiagonalTrendLinesInput and (not showOnlyCurrentSlopeInput or (isDownTrend and fallingResistance))
if allowSupportLine and na(supportTrendLine) and not na(previousSupportPivotPrice) and not na(lastSupportPivotPrice)
    supportTrendLine := line.new(x1 = previousSupportPivotBar, y1 = previousSupportPivotPrice, x2 = lastSupportPivotBar, y2 = lastSupportPivotPrice, xloc = xloc.bar_index, extend = extend.right, color = supportTrendLineColorInput, style = line.style_solid, width = 2)
if allowResistanceLine and na(resistanceTrendLine) and not na(previousResistancePivotPrice) and not na(lastResistancePivotPrice)
    resistanceTrendLine := line.new(x1 = previousResistancePivotBar, y1 = previousResistancePivotPrice, x2 = lastResistancePivotBar, y2 = lastResistancePivotPrice, xloc = xloc.bar_index, extend = extend.right, color = resistanceTrendLineColorInput, style = line.style_solid, width = 2)
if not allowSupportLine and not na(supportTrendLine)
    line.delete(supportTrendLine)
    supportTrendLine := na
if not allowResistanceLine and not na(resistanceTrendLine)
    line.delete(resistanceTrendLine)
    resistanceTrendLine := na

// --- Consolidated horizontal support and resistance levels ---
if showKeyLevelsInput
    float keyLevelTolerance = atrValue * keyLevelToleranceAtrInput
    if not na(pivotLow) and not na(keyLevelTolerance)
        int matchingSupportIndex = -1
        float nearestSupportDistance = na
        int supportCount = array.size(keySupportPrices)
        if supportCount > 0
            for supportIndex = 0 to supportCount - 1
                float supportDistance = math.abs(array.get(keySupportPrices, supportIndex) - pivotLow)
                if supportDistance <= keyLevelTolerance and (na(nearestSupportDistance) or supportDistance < nearestSupportDistance)
                    matchingSupportIndex := supportIndex
                    nearestSupportDistance := supportDistance
        if matchingSupportIndex >= 0
            float mergedSupportPrice = (array.get(keySupportPrices, matchingSupportIndex) + pivotLow) / 2.0
            array.set(keySupportPrices, matchingSupportIndex, mergedSupportPrice)
            array.set(keySupportTouches, matchingSupportIndex, array.get(keySupportTouches, matchingSupportIndex) + 1)
            line supportLevelLine = array.get(keySupportLines, matchingSupportIndex)
            line.set_y1(supportLevelLine, mergedSupportPrice)
            line.set_y2(supportLevelLine, mergedSupportPrice)
        else
            line newSupportLevelLine = line.new(x1 = bar_index - pivotLengthInput, y1 = pivotLow, x2 = bar_index + 1, y2 = pivotLow, xloc = xloc.bar_index, extend = extend.right, color = supportTrendLineColorInput, style = line.style_dotted, width = 1)
            array.unshift(keySupportPrices, pivotLow)
            array.unshift(keySupportTouches, 1)
            array.unshift(keySupportLines, newSupportLevelLine)
        while array.size(keySupportPrices) > keyLevelsCountInput
            line.delete(array.pop(keySupportLines))
            array.pop(keySupportPrices)
            array.pop(keySupportTouches)
    if not na(pivotHigh) and not na(keyLevelTolerance)
        int matchingResistanceIndex = -1
        float nearestResistanceDistance = na
        int resistanceCount = array.size(keyResistancePrices)
        if resistanceCount > 0
            for resistanceIndex = 0 to resistanceCount - 1
                float resistanceDistance = math.abs(array.get(keyResistancePrices, resistanceIndex) - pivotHigh)
                if resistanceDistance <= keyLevelTolerance and (na(nearestResistanceDistance) or resistanceDistance < nearestResistanceDistance)
                    matchingResistanceIndex := resistanceIndex
                    nearestResistanceDistance := resistanceDistance
        if matchingResistanceIndex >= 0
            float mergedResistancePrice = (array.get(keyResistancePrices, matchingResistanceIndex) + pivotHigh) / 2.0
            array.set(keyResistancePrices, matchingResistanceIndex, mergedResistancePrice)
            array.set(keyResistanceTouches, matchingResistanceIndex, array.get(keyResistanceTouches, matchingResistanceIndex) + 1)
            line resistanceLevelLine = array.get(keyResistanceLines, matchingResistanceIndex)
            line.set_y1(resistanceLevelLine, mergedResistancePrice)
            line.set_y2(resistanceLevelLine, mergedResistancePrice)
        else
            line newResistanceLevelLine = line.new(x1 = bar_index - pivotLengthInput, y1 = pivotHigh, x2 = bar_index + 1, y2 = pivotHigh, xloc = xloc.bar_index, extend = extend.right, color = resistanceTrendLineColorInput, style = line.style_dotted, width = 1)
            array.unshift(keyResistancePrices, pivotHigh)
            array.unshift(keyResistanceTouches, 1)
            array.unshift(keyResistanceLines, newResistanceLevelLine)
        while array.size(keyResistancePrices) > keyLevelsCountInput
            line.delete(array.pop(keyResistanceLines))
            array.pop(keyResistancePrices)
            array.pop(keyResistanceTouches)

// --- Automatic parallel trend channel ---
float supportSlope = not na(previousSupportPivotBar) and not na(lastSupportPivotBar) and lastSupportPivotBar != previousSupportPivotBar ? (lastSupportPivotPrice - previousSupportPivotPrice) / (lastSupportPivotBar - previousSupportPivotBar) : na
float supportAtResistance = not na(supportSlope) and not na(lastResistancePivotBar) ? previousSupportPivotPrice + supportSlope * (lastResistancePivotBar - previousSupportPivotBar) : na
bool supportChannelValid = not na(supportAtResistance) and not na(lastResistancePivotPrice) and lastResistancePivotPrice > supportAtResistance
bool activeSupportChannelValid = supportChannelValid and (not showOnlyCurrentSlopeInput or (isUpTrend and supportSlope > 0))
float resistanceSlope = not na(previousResistancePivotBar) and not na(lastResistancePivotBar) and lastResistancePivotBar != previousResistancePivotBar ? (lastResistancePivotPrice - previousResistancePivotPrice) / (lastResistancePivotBar - previousResistancePivotBar) : na
float resistanceAtSupport = not na(resistanceSlope) and not na(lastSupportPivotBar) ? previousResistancePivotPrice + resistanceSlope * (lastSupportPivotBar - previousResistancePivotBar) : na
bool resistanceChannelValid = not na(resistanceAtSupport) and not na(lastSupportPivotPrice) and lastSupportPivotPrice < resistanceAtSupport
bool activeResistanceChannelValid = resistanceChannelValid and (not showOnlyCurrentSlopeInput or (isDownTrend and resistanceSlope < 0))
if showChannelInput and (activeSupportChannelValid or activeResistanceChannelValid)
    int channelLowerX1 = na
    int channelLowerX2 = na
    int channelUpperX1 = na
    int channelUpperX2 = na
    float channelLowerY1 = na
    float channelLowerY2 = na
    float channelUpperY1 = na
    float channelUpperY2 = na
    if activeSupportChannelValid
        float channelWidth = lastResistancePivotPrice - supportAtResistance
        channelLowerX1 := previousSupportPivotBar
        channelLowerX2 := lastSupportPivotBar
        channelUpperX1 := previousSupportPivotBar
        channelUpperX2 := lastSupportPivotBar
        channelLowerY1 := previousSupportPivotPrice
        channelLowerY2 := lastSupportPivotPrice
        channelUpperY1 := previousSupportPivotPrice + channelWidth
        channelUpperY2 := lastSupportPivotPrice + channelWidth
    else
        float channelWidth = resistanceAtSupport - lastSupportPivotPrice
        channelLowerX1 := previousResistancePivotBar
        channelLowerX2 := lastResistancePivotBar
        channelUpperX1 := previousResistancePivotBar
        channelUpperX2 := lastResistancePivotBar
        channelUpperY1 := previousResistancePivotPrice
        channelUpperY2 := lastResistancePivotPrice
        channelLowerY1 := previousResistancePivotPrice - channelWidth
        channelLowerY2 := lastResistancePivotPrice - channelWidth
    if na(channelLowerLine)
        channelLowerLine := line.new(x1 = channelLowerX1, y1 = channelLowerY1, x2 = channelLowerX2, y2 = channelLowerY2, xloc = xloc.bar_index, extend = extend.right, color = channelColorInput, style = line.style_solid, width = 1)
        channelUpperLine := line.new(x1 = channelUpperX1, y1 = channelUpperY1, x2 = channelUpperX2, y2 = channelUpperY2, xloc = xloc.bar_index, extend = extend.right, color = channelColorInput, style = line.style_solid, width = 1)
        channelFill := linefill.new(channelLowerLine, channelUpperLine, color.new(channelColorInput, channelFillTransparencyInput))
    else
        line.set_xy1(channelLowerLine, channelLowerX1, channelLowerY1)
        line.set_xy2(channelLowerLine, channelLowerX2, channelLowerY2)
        line.set_xy1(channelUpperLine, channelUpperX1, channelUpperY1)
        line.set_xy2(channelUpperLine, channelUpperX2, channelUpperY2)
        line.set_color(channelLowerLine, channelColorInput)
        line.set_color(channelUpperLine, channelColorInput)
        linefill.set_color(channelFill, color.new(channelColorInput, channelFillTransparencyInput))
else
    if not na(channelFill)
        linefill.delete(channelFill)
        channelFill := na
    if not na(channelLowerLine)
        line.delete(channelLowerLine)
        channelLowerLine := na
    if not na(channelUpperLine)
        line.delete(channelUpperLine)
        channelUpperLine := na

// --- Trade zone boxes ---
var box profitBox1 = na
var box profitBox2 = na
var box profitBox3 = na
var box lossBox = na
if buySignal or sellSignal
    if not na(profitBox1)
        box.delete(profitBox1)
        profitBox1 := na
    if not na(profitBox2)
        box.delete(profitBox2)
        profitBox2 := na
    if not na(profitBox3)
        box.delete(profitBox3)
        profitBox3 := na
    if not na(lossBox)
        box.delete(lossBox)
        lossBox := na
    if showBoxesInput
        profitBox1 := box.new(left = bar_index, top = math.max(entryLevel, takeProfit1Level), right = bar_index + 1, bottom = math.min(entryLevel, takeProfit1Level), extend = extend.right, border_color = na, border_width = 0, bgcolor = color.new(takeProfit1ColorInput, 92), text = "TP1", text_color = color.white, text_halign = text.align_center, text_valign = text.align_center, text_size = size.small)
        profitBox2 := box.new(left = bar_index, top = math.max(takeProfit1Level, takeProfit2Level), right = bar_index + 1, bottom = math.min(takeProfit1Level, takeProfit2Level), extend = extend.right, border_color = na, border_width = 0, bgcolor = color.new(takeProfit2ColorInput, 94), text = "TP2", text_color = color.white, text_halign = text.align_center, text_valign = text.align_center, text_size = size.small)
        profitBox3 := box.new(left = bar_index, top = math.max(takeProfit2Level, takeProfit3Level), right = bar_index + 1, bottom = math.min(takeProfit2Level, takeProfit3Level), extend = extend.right, border_color = na, border_width = 0, bgcolor = color.new(takeProfit3ColorInput, 95), text = "TP3", text_color = color.white, text_halign = text.align_center, text_valign = text.align_center, text_size = size.small)
        lossBox := box.new(left = bar_index, top = math.max(entryLevel, stopLossLevel), right = bar_index + 1, bottom = math.min(entryLevel, stopLossLevel), extend = extend.right, border_color = na, border_width = 0, bgcolor = color.new(stopLossColorInput, 93), text = "SL", text_color = color.white, text_halign = text.align_center, text_valign = text.align_center, text_size = size.small)
if not showBoxesInput
    if not na(profitBox1)
        box.delete(profitBox1)
        profitBox1 := na
    if not na(profitBox2)
        box.delete(profitBox2)
        profitBox2 := na
    if not na(profitBox3)
        box.delete(profitBox3)
        profitBox3 := na
    if not na(lossBox)
        box.delete(lossBox)
        lossBox := na

// --- Exact price labels ---
var label entryPriceLabel = na
var label takeProfit1PriceLabel = na
var label takeProfit2PriceLabel = na
var label takeProfit3PriceLabel = na
var label stopLossPriceLabel = na
if buySignal or sellSignal
    if not na(entryPriceLabel)
        label.delete(entryPriceLabel)
    if not na(takeProfit1PriceLabel)
        label.delete(takeProfit1PriceLabel)
    if not na(takeProfit2PriceLabel)
        label.delete(takeProfit2PriceLabel)
    if not na(takeProfit3PriceLabel)
        label.delete(takeProfit3PriceLabel)
    if not na(stopLossPriceLabel)
        label.delete(stopLossPriceLabel)
    entryPriceLabel := na
    takeProfit1PriceLabel := na
    takeProfit2PriceLabel := na
    takeProfit3PriceLabel := na
    stopLossPriceLabel := na
if showPriceLabelsInput and not na(entryLevel)
    if na(entryPriceLabel)
        entryPriceLabel := createPriceLabel(bar_index + priceLabelOffsetInput, entryLevel, "Entry", entryColorInput)
        takeProfit1PriceLabel := createPriceLabel(bar_index + priceLabelOffsetInput, takeProfit1Level, "TP1", takeProfit1ColorInput)
        takeProfit2PriceLabel := createPriceLabel(bar_index + priceLabelOffsetInput, takeProfit2Level, "TP2", takeProfit2ColorInput)
        takeProfit3PriceLabel := createPriceLabel(bar_index + priceLabelOffsetInput, takeProfit3Level, "TP3", takeProfit3ColorInput)
        stopLossPriceLabel := createPriceLabel(bar_index + priceLabelOffsetInput, stopLossLevel, "SL", stopLossColorInput)
    label.set_x(entryPriceLabel, bar_index + priceLabelOffsetInput)
    label.set_x(takeProfit1PriceLabel, bar_index + priceLabelOffsetInput)
    label.set_x(takeProfit2PriceLabel, bar_index + priceLabelOffsetInput)
    label.set_x(takeProfit3PriceLabel, bar_index + priceLabelOffsetInput)
    label.set_x(stopLossPriceLabel, bar_index + priceLabelOffsetInput)
if not showPriceLabelsInput
    if not na(entryPriceLabel)
        label.delete(entryPriceLabel)
        entryPriceLabel := na
    if not na(takeProfit1PriceLabel)
        label.delete(takeProfit1PriceLabel)
        takeProfit1PriceLabel := na
    if not na(takeProfit2PriceLabel)
        label.delete(takeProfit2PriceLabel)
        takeProfit2PriceLabel := na
    if not na(takeProfit3PriceLabel)
        label.delete(takeProfit3PriceLabel)
        takeProfit3PriceLabel := na
    if not na(stopLossPriceLabel)
        label.delete(stopLossPriceLabel)
        stopLossPriceLabel := na

// --- Plots and chart coloring ---
upTrendPlot = plot(showTrendLinesInput ? upTrend : na, "Uptrend", color = upColorInput, linewidth = 2, style = plot.style_linebr)
downTrendPlot = plot(showTrendLinesInput ? downTrend : na, "Downtrend", color = downColorInput, linewidth = 2, style = plot.style_linebr)
plot(useEma200FilterInput ? ema200Value : na, "EMA 200 filter", color = color.new(chart.fg_color, 15), linewidth = 2)
plot(enableEmaReentryInput or enableAggressiveEmaReentryInput ? emaReentryValue : na, "Re-entry EMA", color = entryColorInput, linewidth = 1)
priceReferencePlot = plot(showFillInput ? close : na, "Trend area reference", display = display.none)
fill(priceReferencePlot, upTrendPlot, color = color.new(upColorInput, 88), title = "Uptrend area")
fill(priceReferencePlot, downTrendPlot, color = color.new(downColorInput, 88), title = "Downtrend area")
plotshape(showSignalsInput and buySignal, title = "Buy signal", style = shape.labelup, location = location.belowbar, color = upColorInput, text = "BUY", textcolor = color.white, size = size.tiny)
plotshape(showSignalsInput and sellSignal, title = "Sell signal", style = shape.labeldown, location = location.abovebar, color = downColorInput, text = "SELL", textcolor = color.white, size = size.tiny)
plotshape(showTpMarksInput and takeProfit1HitEvent ? takeProfit1Level : na, title = "TP1 reached", style = shape.labelup, location = location.absolute, color = takeProfit1ColorInput, text = "✓ TP1", textcolor = color.white, size = size.tiny)
plotshape(showTpMarksInput and takeProfit2HitEvent ? takeProfit2Level : na, title = "TP2 reached", style = shape.labelup, location = location.absolute, color = takeProfit2ColorInput, text = "✓ TP2", textcolor = color.white, size = size.tiny)
plotshape(showTpMarksInput and takeProfit3HitEvent ? takeProfit3Level : na, title = "TP3 reached", style = shape.labelup, location = location.absolute, color = takeProfit3ColorInput, text = "✓ TP3", textcolor = color.white, size = size.tiny)
barcolor(showCandleColorsInput ? (isUpTrend ? color.new(candleUpColorInput, candleTransparencyInput) : isDownTrend ? color.new(candleDownColorInput, candleTransparencyInput) : na) : na)

// --- Alert conditions ---
alertcondition(buySignal, "Supertrend Buy", "Supertrend BUY on {{ticker}} at {{close}}")
alertcondition(sellSignal, "Supertrend Sell", "Supertrend SELL on {{ticker}} at {{close}}")
alertcondition(takeProfit1HitEvent, "TP1 reached", "TP1 reached on {{ticker}} at {{close}}")
alertcondition(takeProfit2HitEvent, "TP2 reached", "TP2 reached on {{ticker}} at {{close}}")
alertcondition(takeProfit3HitEvent, "TP3 reached", "TP3 reached on {{ticker}} at {{close}}")

// --- Win-rate table ---
var table statsTable = table.new(position.top_right, 2, 7, bgcolor = color.new(chart.bg_color, 10), frame_color = color.new(chart.fg_color, 100), frame_width = 0, border_color = color.new(chart.fg_color, 100), border_width = 0)
if barstate.islast
    if showStatsInput
        int closedTrades = winningTrades + losingTrades
        string winRateText = closedTrades > 0 ? str.tostring(100.0 * winningTrades / closedTrades, "#.##") + " %" : "n/a"
        table.cell(statsTable, 0, 0, "Supertrend statistics", text_color = chart.fg_color, bgcolor = color.new(entryColorInput, 70), text_size = size.small)
        table.cell(statsTable, 1, 0, "", text_color = chart.fg_color, bgcolor = color.new(entryColorInput, 70), text_size = size.small)
        table.cell(statsTable, 0, 1, "Signals", text_color = chart.fg_color, text_size = size.small)
        table.cell(statsTable, 1, 1, str.tostring(totalSignals), text_color = chart.fg_color, text_size = size.small)
        table.cell(statsTable, 0, 2, "Evaluated", text_color = chart.fg_color, text_size = size.small)
        table.cell(statsTable, 1, 2, str.tostring(closedTrades), text_color = chart.fg_color, text_size = size.small)
        table.cell(statsTable, 0, 3, "Wins (TP1)", text_color = upColorInput, text_size = size.small)
        table.cell(statsTable, 1, 3, str.tostring(winningTrades), text_color = upColorInput, text_size = size.small)
        table.cell(statsTable, 0, 4, "Losses (SL)", text_color = downColorInput, text_size = size.small)
        table.cell(statsTable, 1, 4, str.tostring(losingTrades), text_color = downColorInput, text_size = size.small)
        table.cell(statsTable, 0, 5, "Win rate (TP1)", text_color = chart.fg_color, text_size = size.small)
        table.cell(statsTable, 1, 5, winRateText, text_color = chart.fg_color, text_size = size.small)
        table.cell(statsTable, 0, 6, "Profit (R)", text_color = totalProfitR >= 0 ? upColorInput : downColorInput, text_size = size.small)
        table.cell(statsTable, 1, 6, str.tostring(totalProfitR, "#.##") + " R", text_color = totalProfitR >= 0 ? upColorInput : downColorInput, text_size = size.small)
    else
        table.clear(statsTable, 0, 0, 1, 6)

// --- ADX dashboard ---
string adxPhase = na(adxValue) ? "Waiting for data" : adxValue < adxRangeThresholdInput ? "Range" : adxValue < adxStrongThresholdInput ? "Transition" : "Strong trend"
color adxPhaseColor = adxPhase == "Strong trend" ? upColorInput : adxPhase == "Range" ? downColorInput : chart.fg_color
string adxDirectionText = na(adxValue) ? "n/a" : diPlus > diMinus ? "Bullish" : diMinus > diPlus ? "Bearish" : "Neutral"
bool adxFilterActive = not na(adxValue) and adxValue >= adxStrongThresholdInput and ((isUpTrend and diPlus > diMinus) or (isDownTrend and diMinus > diPlus))
var table adxDashboardTable = table.new(position.middle_right, 2, 8, bgcolor = color.new(chart.bg_color, 10), frame_color = color.new(chart.fg_color, 100), frame_width = 0, border_color = color.new(chart.fg_color, 100), border_width = 0)
if barstate.islast
    if showAdxDashboardInput
        table.cell(adxDashboardTable, 0, 0, "ADX dashboard", text_color = chart.fg_color, bgcolor = color.new(entryColorInput, 70), text_size = size.small)
        table.cell(adxDashboardTable, 1, 0, "", text_color = chart.fg_color, bgcolor = color.new(entryColorInput, 70), text_size = size.small)
        table.cell(adxDashboardTable, 0, 1, "ADX", text_color = chart.fg_color, text_size = size.small)
        table.cell(adxDashboardTable, 1, 1, na(adxValue) ? "n/a" : str.tostring(adxValue, "#.##"), text_color = adxPhaseColor, text_size = size.small)
        table.cell(adxDashboardTable, 0, 2, "+DI", text_color = upColorInput, text_size = size.small)
        table.cell(adxDashboardTable, 1, 2, na(diPlus) ? "n/a" : str.tostring(diPlus, "#.##"), text_color = upColorInput, text_size = size.small)
        table.cell(adxDashboardTable, 0, 3, "-DI", text_color = downColorInput, text_size = size.small)
        table.cell(adxDashboardTable, 1, 3, na(diMinus) ? "n/a" : str.tostring(diMinus, "#.##"), text_color = downColorInput, text_size = size.small)
        table.cell(adxDashboardTable, 0, 4, "Market phase", text_color = chart.fg_color, text_size = size.small)
        table.cell(adxDashboardTable, 1, 4, adxPhase, text_color = adxPhaseColor, text_size = size.small)
        table.cell(adxDashboardTable, 0, 5, "DI direction", text_color = chart.fg_color, text_size = size.small)
        table.cell(adxDashboardTable, 1, 5, adxDirectionText, text_color = adxDirectionText == "Bullish" ? upColorInput : adxDirectionText == "Bearish" ? downColorInput : chart.fg_color, text_size = size.small)
        table.cell(adxDashboardTable, 0, 6, "Supertrend", text_color = chart.fg_color, text_size = size.small)
        table.cell(adxDashboardTable, 1, 6, isUpTrend ? "Uptrend" : isDownTrend ? "Downtrend" : "n/a", text_color = isUpTrend ? upColorInput : downColorInput, text_size = size.small)
        table.cell(adxDashboardTable, 0, 7, "Filter", text_color = chart.fg_color, text_size = size.small)
        table.cell(adxDashboardTable, 1, 7, adxFilterActive ? "Trend eligible" : "Wait", text_color = adxFilterActive ? upColorInput : downColorInput, text_size = size.small)
    else
        table.clear(adxDashboardTable, 0, 0, 1, 7)

// --- Multi-timeframe dashboard ---
var table mtfDashboardTable = table.new(position.bottom_right, 3, 6, bgcolor = color.new(chart.bg_color, 10), frame_color = color.new(chart.fg_color, 100), frame_width = 0, border_color = color.new(chart.fg_color, 100), border_width = 0)
if barstate.islast
    if showMtfDashboardInput
        table.cell(mtfDashboardTable, 0, 0, "Timeframe", text_color = chart.fg_color, bgcolor = color.new(entryColorInput, 70), text_size = size.small)
        table.cell(mtfDashboardTable, 1, 0, "Score", text_color = chart.fg_color, bgcolor = color.new(entryColorInput, 70), text_size = size.small)
        table.cell(mtfDashboardTable, 2, 0, "Direction", text_color = chart.fg_color, bgcolor = color.new(entryColorInput, 70), text_size = size.small)
        table.cell(mtfDashboardTable, 0, 1, "5m", text_color = chart.fg_color, text_size = size.small)
        table.cell(mtfDashboardTable, 1, 1, str.tostring(score5m, "#.##"), text_color = scoreColor(score5m), text_size = size.small)
        table.cell(mtfDashboardTable, 2, 1, state5m, text_color = state5m == "Bullish" ? upColorInput : state5m == "Bearish" ? downColorInput : chart.fg_color, text_size = size.small)
        table.cell(mtfDashboardTable, 0, 2, "15m", text_color = chart.fg_color, text_size = size.small)
        table.cell(mtfDashboardTable, 1, 2, str.tostring(score15m, "#.##"), text_color = scoreColor(score15m), text_size = size.small)
        table.cell(mtfDashboardTable, 2, 2, state15m, text_color = state15m == "Bullish" ? upColorInput : state15m == "Bearish" ? downColorInput : chart.fg_color, text_size = size.small)
        table.cell(mtfDashboardTable, 0, 3, "1h", text_color = chart.fg_color, text_size = size.small)
        table.cell(mtfDashboardTable, 1, 3, str.tostring(score1h, "#.##"), text_color = scoreColor(score1h), text_size = size.small)
        table.cell(mtfDashboardTable, 2, 3, state1h, text_color = state1h == "Bullish" ? upColorInput : state1h == "Bearish" ? downColorInput : chart.fg_color, text_size = size.small)
        table.cell(mtfDashboardTable, 0, 4, "4h", text_color = chart.fg_color, text_size = size.small)
        table.cell(mtfDashboardTable, 1, 4, str.tostring(score4h, "#.##"), text_color = scoreColor(score4h), text_size = size.small)
        table.cell(mtfDashboardTable, 2, 4, state4h, text_color = state4h == "Bullish" ? upColorInput : state4h == "Bearish" ? downColorInput : chart.fg_color, text_size = size.small)
        table.cell(mtfDashboardTable, 0, 5, "1D", text_color = chart.fg_color, text_size = size.small)
        table.cell(mtfDashboardTable, 1, 5, str.tostring(score1d, "#.##"), text_color = scoreColor(score1d), text_size = size.small)
        table.cell(mtfDashboardTable, 2, 5, state1d, text_color = state1d == "Bullish" ? upColorInput : state1d == "Bearish" ? downColorInput : chart.fg_color, text_size = size.small)
    else
        table.clear(mtfDashboardTable, 0, 0, 2, 5)

// --- Recent trade history dashboard ---
var table tradeHistoryTable = table.new(position.middle_left, 5, 11, bgcolor = color.new(chart.bg_color, 10), frame_color = color.new(chart.fg_color, 100), frame_width = 0, border_color = color.new(chart.fg_color, 100), border_width = 0)
if barstate.islast
    if showTradeHistoryInput
        table.cell(tradeHistoryTable, 0, 0, "#", text_color = chart.fg_color, bgcolor = color.new(entryColorInput, 70), text_size = size.small)
        table.cell(tradeHistoryTable, 1, 0, "Direction", text_color = chart.fg_color, bgcolor = color.new(entryColorInput, 70), text_size = size.small)
        table.cell(tradeHistoryTable, 2, 0, "Outcome", text_color = chart.fg_color, bgcolor = color.new(entryColorInput, 70), text_size = size.small)
        table.cell(tradeHistoryTable, 3, 0, "R:R", text_color = chart.fg_color, bgcolor = color.new(entryColorInput, 70), text_size = size.small)
        table.cell(tradeHistoryTable, 4, 0, "Stopped out", text_color = chart.fg_color, bgcolor = color.new(entryColorInput, 70), text_size = size.small)
        for historyIndex = 0 to 9
            int historyRow = historyIndex + 1
            if historyIndex < array.size(tradeDirectionHistory)
                string historyDirection = array.get(tradeDirectionHistory, historyIndex)
                string historyOutcome = array.get(tradeOutcomeHistory, historyIndex)
                float historyRr = array.get(tradeRrHistory, historyIndex)
                string historySl = array.get(tradeSlHistory, historyIndex)
                table.cell(tradeHistoryTable, 0, historyRow, str.tostring(historyRow), text_color = chart.fg_color, text_size = size.small)
                table.cell(tradeHistoryTable, 1, historyRow, historyDirection, text_color = historyDirection == "Long" ? upColorInput : downColorInput, text_size = size.small)
                table.cell(tradeHistoryTable, 2, historyRow, historyOutcome, text_color = historyOutcome == "SL" ? downColorInput : upColorInput, text_size = size.small)
                table.cell(tradeHistoryTable, 3, historyRow, str.tostring(historyRr, "#.##") + "R", text_color = historyRr >= 0 ? upColorInput : downColorInput, text_size = size.small)
                table.cell(tradeHistoryTable, 4, historyRow, historySl, text_color = historySl == "Yes" ? downColorInput : upColorInput, text_size = size.small)
            else
                table.cell(tradeHistoryTable, 0, historyRow, "", text_color = chart.fg_color, text_size = size.small)
                table.cell(tradeHistoryTable, 1, historyRow, "", text_color = chart.fg_color, text_size = size.small)
                table.cell(tradeHistoryTable, 2, historyRow, "", text_color = chart.fg_color, text_size = size.small)
                table.cell(tradeHistoryTable, 3, historyRow, "", text_color = chart.fg_color, text_size = size.small)
                table.cell(tradeHistoryTable, 4, historyRow, "", text_color = chart.fg_color, text_size = size.small)
    else
        table.clear(tradeHistoryTable, 0, 0, 4, 10)
